"""
Mock辅助工具

提供各种Mock对象和辅助函数，用于模拟外部依赖。
"""

from unittest.mock import Mock, MagicMock, patch
from typing import Dict, Any, List, Optional
from pathlib import Path
import json


class MockFFmpeg:
    """Mock FFmpeg工具"""
    
    def __init__(self):
        self.probe_data = {
            'streams': [
                {
                    'codec_type': 'video',
                    'width': 1920,
                    'height': 1080,
                    'duration': '10.0',
                    'avg_frame_rate': '30/1',
                    'codec_name': 'h264'
                }
            ],
            'format': {
                'duration': '10.0',
                'size': '1048576',
                'format_name': 'mp4,mov,m4a,3gp,3g2,mj2'
            }
        }
        self.run_output = (b'', b'')
    
    def create_mock(self):
        """创建FFmpeg Mock对象"""
        mock = Mock()
        mock.probe.return_value = self.probe_data
        mock.run.return_value = self.run_output
        return mock
    
    def set_probe_data(self, **kwargs):
        """设置probe返回数据"""
        if 'width' in kwargs:
            self.probe_data['streams'][0]['width'] = kwargs['width']
        if 'height' in kwargs:
            self.probe_data['streams'][0]['height'] = kwargs['height']
        if 'duration' in kwargs:
            duration = str(kwargs['duration'])
            self.probe_data['streams'][0]['duration'] = duration
            self.probe_data['format']['duration'] = duration
        if 'fps' in kwargs:
            self.probe_data['streams'][0]['avg_frame_rate'] = f"{kwargs['fps']}/1"
        if 'format' in kwargs:
            self.probe_data['format']['format_name'] = kwargs['format']
        if 'codec' in kwargs:
            self.probe_data['streams'][0]['codec_name'] = kwargs['codec']
        if 'size' in kwargs:
            self.probe_data['format']['size'] = str(kwargs['size'])
    
    def set_run_output(self, stdout: bytes = b'', stderr: bytes = b''):
        """设置run命令输出"""
        self.run_output = (stdout, stderr)
    
    def simulate_error(self, error_message: str = "FFmpeg error"):
        """模拟FFmpeg错误"""
        def side_effect(*args, **kwargs):
            raise Exception(error_message)
        
        mock = self.create_mock()
        mock.run.side_effect = side_effect
        return mock


class MockOpenCV:
    """Mock OpenCV工具"""
    
    def __init__(self):
        self.video_properties = {
            3: 1920,  # CV_CAP_PROP_FRAME_WIDTH
            4: 1080,  # CV_CAP_PROP_FRAME_HEIGHT
            5: 30.0,  # CV_CAP_PROP_FPS
            7: 300    # CV_CAP_PROP_FRAME_COUNT
        }
        self.frame_data = None
        self.read_success = True
    
    def create_mock(self):
        """创建OpenCV Mock对象"""
        mock = Mock()
        
        # Mock VideoCapture
        video_capture = Mock()
        video_capture.get.side_effect = lambda prop: self.video_properties.get(prop, 0)
        video_capture.read.return_value = (self.read_success, self.frame_data)
        video_capture.isOpened.return_value = True
        video_capture.release.return_value = None
        
        mock.VideoCapture.return_value = video_capture
        
        # Mock 其他常用函数
        mock.imread.return_value = Mock()  # 模拟图像数据
        mock.imwrite.return_value = True
        mock.cvtColor.return_value = Mock()
        
        return mock
    
    def set_video_properties(self, width=None, height=None, fps=None, frame_count=None):
        """设置视频属性"""
        if width is not None:
            self.video_properties[3] = width
        if height is not None:
            self.video_properties[4] = height
        if fps is not None:
            self.video_properties[5] = fps
        if frame_count is not None:
            self.video_properties[7] = frame_count
    
    def set_frame_data(self, frame_data, success=True):
        """设置帧数据"""
        self.frame_data = frame_data
        self.read_success = success
    
    def simulate_video_open_error(self):
        """模拟视频打开失败"""
        mock = self.create_mock()
        mock.VideoCapture.return_value.isOpened.return_value = False
        return mock


class MockGeminiAPI:
    """Mock Gemini API工具"""
    
    def __init__(self):
        self.response_data = {
            'category': 'product_showcase',
            'confidence': 0.85,
            'reasoning': '视频展示了产品的特性和使用方法',
            'features': ['product', 'demonstration']
        }
        self.should_raise_error = False
        self.error_message = "API调用失败"
    
    def create_mock(self):
        """创建Gemini API Mock对象"""
        mock = Mock()
        
        if self.should_raise_error:
            mock.generate_content.side_effect = Exception(self.error_message)
        else:
            response_mock = Mock()
            response_mock.text = json.dumps(self.response_data, ensure_ascii=False)
            mock.generate_content.return_value = response_mock
        
        return mock
    
    def set_response_data(self, **kwargs):
        """设置API响应数据"""
        self.response_data.update(kwargs)
    
    def simulate_error(self, error_message: str = "API调用失败"):
        """模拟API错误"""
        self.should_raise_error = True
        self.error_message = error_message
    
    def reset_error(self):
        """重置错误状态"""
        self.should_raise_error = False


class MockVideoFile:
    """Mock视频文件工具"""
    
    def __init__(self, file_path: str):
        self.file_path = Path(file_path)
        self.exists = True
        self.size = 1048576  # 1MB
        self.is_file = True
    
    def create_mock_path(self):
        """创建Mock Path对象"""
        mock_path = Mock(spec=Path)
        mock_path.exists.return_value = self.exists
        mock_path.is_file.return_value = self.is_file
        mock_path.stat.return_value.st_size = self.size
        mock_path.name = self.file_path.name
        mock_path.suffix = self.file_path.suffix
        mock_path.__str__ = lambda: str(self.file_path)
        mock_path.__fspath__ = lambda: str(self.file_path)
        return mock_path
    
    def set_exists(self, exists: bool):
        """设置文件是否存在"""
        self.exists = exists
    
    def set_size(self, size: int):
        """设置文件大小"""
        self.size = size
    
    def set_is_file(self, is_file: bool):
        """设置是否为文件"""
        self.is_file = is_file


def create_mock_video_processor():
    """创建Mock视频处理器"""
    mock = Mock()
    
    # Mock 元数据提取
    mock.extract_metadata.return_value = {
        'duration': 10.0,
        'width': 1920,
        'height': 1080,
        'fps': 30.0,
        'format': 'mp4',
        'codec': 'h264',
        'size': 1048576
    }
    
    # Mock 视频分析
    mock.analyze_content.return_value = {
        'scene_count': 5,
        'avg_brightness': 0.6,
        'motion_level': 'medium',
        'quality_score': 0.8
    }
    
    # Mock 视频切片
    mock.slice_video.return_value = {
        'success': True,
        'slices': [
            {'start': 0, 'end': 5, 'path': '/output/slice_1.mp4'},
            {'start': 5, 'end': 10, 'path': '/output/slice_2.mp4'}
        ]
    }
    
    return mock


def create_mock_database_session():
    """创建Mock数据库会话"""
    mock_session = Mock()
    
    # Mock 基本操作
    mock_session.add.return_value = None
    mock_session.commit.return_value = None
    mock_session.rollback.return_value = None
    mock_session.close.return_value = None
    
    # Mock 查询操作
    mock_query = Mock()
    mock_query.filter.return_value = mock_query
    mock_query.filter_by.return_value = mock_query
    mock_query.order_by.return_value = mock_query
    mock_query.limit.return_value = mock_query
    mock_query.offset.return_value = mock_query
    mock_query.first.return_value = None
    mock_query.all.return_value = []
    mock_query.count.return_value = 0
    
    mock_session.query.return_value = mock_query
    
    return mock_session


def create_mock_file_system(temp_dir: Path):
    """创建Mock文件系统"""
    mock_fs = Mock()
    
    def mock_exists(path):
        return (temp_dir / path).exists()
    
    def mock_is_file(path):
        return (temp_dir / path).is_file()
    
    def mock_is_dir(path):
        return (temp_dir / path).is_dir()
    
    def mock_mkdir(path, parents=False, exist_ok=False):
        (temp_dir / path).mkdir(parents=parents, exist_ok=exist_ok)
    
    def mock_write_text(path, content, encoding='utf-8'):
        (temp_dir / path).write_text(content, encoding=encoding)
    
    def mock_read_text(path, encoding='utf-8'):
        return (temp_dir / path).read_text(encoding=encoding)
    
    mock_fs.exists = mock_exists
    mock_fs.is_file = mock_is_file
    mock_fs.is_dir = mock_is_dir
    mock_fs.mkdir = mock_mkdir
    mock_fs.write_text = mock_write_text
    mock_fs.read_text = mock_read_text
    
    return mock_fs


class MockWorkflowExecutor:
    """Mock工作流执行器"""
    
    def __init__(self):
        self.execution_result = {
            'success': True,
            'results': {},
            'execution_time': 1.5,
            'completed_nodes': [],
            'failed_nodes': []
        }
        self.should_fail = False
        self.failure_reason = "执行失败"
    
    def create_mock(self):
        """创建Mock执行器"""
        mock = Mock()
        
        if self.should_fail:
            mock.execute.side_effect = Exception(self.failure_reason)
        else:
            mock.execute.return_value = self.execution_result
        
        mock.status = Mock()
        mock.status.value = 'completed' if not self.should_fail else 'failed'
        
        return mock
    
    def set_execution_result(self, **kwargs):
        """设置执行结果"""
        self.execution_result.update(kwargs)
    
    def simulate_failure(self, reason: str = "执行失败"):
        """模拟执行失败"""
        self.should_fail = True
        self.failure_reason = reason
    
    def reset_failure(self):
        """重置失败状态"""
        self.should_fail = False


# ============================================================================
# 上下文管理器
# ============================================================================

class MockContext:
    """Mock上下文管理器"""
    
    def __init__(self):
        self.patches = []
    
    def patch(self, target, **kwargs):
        """添加patch"""
        patcher = patch(target, **kwargs)
        self.patches.append(patcher)
        return patcher.start()
    
    def __enter__(self):
        return self
    
    def __exit__(self, exc_type, exc_val, exc_tb):
        for patcher in reversed(self.patches):
            try:
                patcher.stop()
            except:
                pass


# ============================================================================
# 便捷函数
# ============================================================================

def mock_async_function(return_value=None, side_effect=None):
    """创建异步函数Mock"""
    import asyncio
    
    async def async_mock(*args, **kwargs):
        if side_effect:
            if callable(side_effect):
                result = side_effect(*args, **kwargs)
                if asyncio.iscoroutine(result):
                    return await result
                return result
            else:
                raise side_effect
        return return_value
    
    mock = Mock()
    mock.side_effect = async_mock
    return mock


def create_test_video_files(temp_dir: Path, count: int = 3) -> List[Path]:
    """创建测试视频文件"""
    files = []
    for i in range(count):
        video_file = temp_dir / f"test_video_{i}.mp4"
        video_file.write_bytes(b'\x00' * (1024 * (i + 1)))
        files.append(video_file)
    return files


def create_test_config_file(temp_dir: Path, config_data: Dict[str, Any]) -> Path:
    """创建测试配置文件"""
    import yaml
    config_file = temp_dir / "test_config.yaml"
    with open(config_file, 'w', encoding='utf-8') as f:
        yaml.dump(config_data, f, default_flow_style=False, allow_unicode=True)
    return config_file
